﻿/// <summary>
/// https://leetcode-cn.com/problems/valid-sudoku/
/// </summary>
public class Solution
{
    private class Board
    {
        private readonly Square[,] squares = new Square[9, 9];

        public bool TrySetValue(int row, int col, int value)
        {
            return this.squares[row, col].TrySetValue(value);
        }

        public Board()
        {
            // 0
            // 1
            // 2
            // 3
            // 4
            // 5
            // 6
            // 7
            // 8
            var rowBlocks = new Square.SquareBlock[9]
                {
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                };
            // 0 1 2 3 4 5 6 7 8
            var colBlocks = new Square.SquareBlock[9]
                {
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                };

            // 0 1 2
            // 3 4 5
            // 6 7 8
            var zoneBlocks = new Square.SquareBlock[9]
                {
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                    new Square.SquareBlock(),
                };

            for (int i = 0; i < 9; i++)
            {
                this.squares[0, i] = new Square(rowBlocks[0], colBlocks[i], zoneBlocks[0 + i / 3]);
                this.squares[1, i] = new Square(rowBlocks[1], colBlocks[i], zoneBlocks[0 + i / 3]);
                this.squares[2, i] = new Square(rowBlocks[2], colBlocks[i], zoneBlocks[0 + i / 3]);
                this.squares[3, i] = new Square(rowBlocks[3], colBlocks[i], zoneBlocks[3 + i / 3]);
                this.squares[4, i] = new Square(rowBlocks[4], colBlocks[i], zoneBlocks[3 + i / 3]);
                this.squares[5, i] = new Square(rowBlocks[5], colBlocks[i], zoneBlocks[3 + i / 3]);
                this.squares[6, i] = new Square(rowBlocks[6], colBlocks[i], zoneBlocks[6 + i / 3]);
                this.squares[7, i] = new Square(rowBlocks[7], colBlocks[i], zoneBlocks[6 + i / 3]);
                this.squares[8, i] = new Square(rowBlocks[8], colBlocks[i], zoneBlocks[6 + i / 3]);
            }
        }

        private class Square
        {
            public class SquareBlock
            {
                public SquareBlock() { }

                /// <summary>
                /// 由 <see cref="Square"/> 类进行添加，完成构建后不应该再修改。
                /// </summary>
                public IList<Square> Squares { get; } = new List<Square>(9);

                public bool IsValueUsed(int value)
                {
                    if (value is >= 1 and <= 9)
                        return this.Squares.Select(item => item.Value).Contains(value);
                    return false;
                }
            }

            public Square(params SquareBlock[] blocks)
                : this(blocks.AsEnumerable()) { }

            public Square(IEnumerable<SquareBlock> blocks)
            {
                this.Blocks = blocks.ToArray();
                foreach (var block in blocks)
                    block.Squares.Add(this);
                this.Value = -1;
            }

            /// <summary>
            /// <code>-1</code> 表示没有填入。
            /// </summary>
            public int Value { get; private set; }

            public IEnumerable<SquareBlock> Blocks { get; }

            public bool TrySetValue(int value)
            {
                if (value is >= 1 and <= 9)
                {
                    var isUsed = false;
                    foreach (var block in this.Blocks)
                    {
                        if (block.IsValueUsed(value))
                        {
                            isUsed = true;
                            break;
                        }
                    }
                    if (isUsed)
                        return false;
                    this.Value = value;
                    return true;
                }
                return false;
            }
            public void RemoveValue()
            {
                this.Value = -1;
            }
        }
    }

    public bool IsValidSudoku(char[][] board)
    {
        var sudukuBoard = new Board();
        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                var c = board[i][j];
                if (c != '.' && !sudukuBoard.TrySetValue(i, j, c - '0'))
                    return false;
            }
        }
        return true;
    }
}